home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Software Vault: The Gold Collection
/
Software Vault - The Gold Collection (American Databankers) (1993).ISO
/
cdr49
/
134_01.zip
/
CTOA.C
< prev
next >
Wrap
Text File
|
1993-06-12
|
20KB
|
905 lines
/* CTOA -- BDS `C' CRL-to-ASM postprocessor- part 1. */
/*
Kevin B. Kenny
729-A E. Cochise Dr.
Phoenix, AZ 85020
*/
/* Copyright (c) 1983 by Kevin B. Kenny
Released to the BDS `C' Users' Group for non-commercial distribution
only. */
/* This program is a utility that generates assembly language (.CSM)
source files for BDS `C' programs. It accepts the .CRL file for the
object instructions, the .CDB file for the symbols, and the .C source
file for commentary. From these, it produces a .CSM file that generate
the same object code.
Syntax:
ctoa source_file [>output_file]
*/
#include <bdscio.h>
#include <dio.h>
#include <cmdutil.h>
#include "ctoatbls.h"
#include "ctoa.h"
#define TITLE "CTOA version 83-11-11 copyright (c) 1983 by Kevin Kenny.\n"
/* Main program */
main (argc, argv)
int argc;
char * * argv;
{
/* Check command syntax */
dioinit (&argc, argv);
if (argc != 2) {
fprintf (STD_ERR, "Usage: ctoa filename [>outfile]\n");
quit ();
}
fprintf (STD_ERR, TITLE);
/* Pick up the source file name, and open the source */
strcpy (srcfnam, argv [1]);
if (fopen (srcfnam, srcfile) == ERROR) {
fprintf (STD_ERR, "Can't open %s: %s\n", srcfnam,
errmsg (errno ()));
quit ();
}
/* Acquire the opcode table */
opc_tabl = opctabl ();
/* Go get the .CRL and .CDB files */
initcdb ();
initcrl ();
/* Process the content of the .CRL file */
proccrl ();
/* Flush any remaining text from the source file, and close it. */
while (!seof) sscan ();
printf ("\n\n\tend\n");
fclose (srcfile);
if (cdbopen) cclose (cdbfile);
/* Flush out directed I/O */
dioflush ();
}
/* Set up processing of the .CRL file for object text */
initcrl() {
/* Get the .CRL file name */
strcpy (crlfnam, srcfnam);
makeext (crlfnam, "CRL");
/* Open the .CRL file, and read in the directory from it */
tcopen (crlfile, crlfnam);
tcseek (crlfile, 0, CABS, crlfnam);
tcread (crlfile, crldir, sizeof crldir, crlfnam);
/* Print a heading on the CSM file indicating the file name and
compilation options. */
printf (";\t%s\tBDS `C' object code of %s\n", crlfnam, srcfnam);
printf (";\t\t\tCompilation options:");
if (havecdb) printf (" -k");
if (crldir.crleflag == 0xBD)
printf (" -e %04x", crldir.crleloc);
printf ("\n");
printf (";\t\t\tExternals use %d (0x%04x) bytes.\n",
crldir.crlelen, crldir.crlelen);
printf ("\n\tMACLIB\t<BDS.LIB>\n\n");
if (crldir.crleflag == 0xBD)
printf ("SYS$EXTFLAG\tSET\t0BDH\nSYS$EXTADDR\tSET\t0%04xH\n",
crldir.crleloc);
printf ("SYS$EXTSIZE\tSET\t0%04xH\n\n", crldir.crlelen);
/* Print non-library-defined CCC symbols on the .CSM file. */
initccc ();
}
/* Process the functions on a .CRL file */
proccrl () {
union { /* .CRL directory pointer */
char * c;
int * i;
} dirp;
/* Point dirp to the start of the directory */
dirp.c = & (crldir.crldtext);
/* Walk through the directory, doing functions one by one */
for (;;) {
strcpy70 (fname, dirp.c); /* Get function name */
if (!*fname) break; /* Return if end of file */
dirp.c += strlen (fname); /* Advance directory pointer */
faddr = *dirp.i++; /* Get function address */
procfunc (); /* Process the function */
}
cclose (crlfile); /* All done; close file */
}
/* Do one function from a .CRL file */
procfunc () {
/* Announce ourselves */
fprintf (STD_ERR, "; Processing the %s function:\n", fname);
/* Find the function on the source and .CDB files. */
sfunct (fname);
cdbfunct (fname);
/* Put the FUNCTION statement on the .CSM file */
printf ("\n\tFUNCTION\t%s\n\n", fname);
/* Process the external references from the function */
procexts ();
/* Output the stack frame layout */
doframe ();
/* Read in the function text and relocation */
if (!readfunc ()) {
fprintf (STD_ERR, ";*** Function is too large to analyze.\n");
fprintf (STD_ERR, ";*** Break it up and try again.\n");
}
else {
/* Construct the label table */
bldlbtab ();
/* Output the code */
asmcode ();
/* Get rid of allocated memory */
freefunc ();
}
/* Find the end of the function on the source */
sendfn ();
/* Put the ENDFUNC statement on the .CSM file */
printf (";\n\tENDFUNC\t\t%s\n;\n", fname);
}
/* Process the external reference directory from a function on the
.CRL file */
procexts () {
int extdlen; /* Length of the external directory */
char syname [NAMLEN]; /* Name of an external symbol */
char * xnamp; /* Pointer to current char in name */
/* Position to the start of the function's external directory */
extdlen = 0;
tcseek (crlfile, faddr, CABS, crlfnam);
nexts = 0; /* No externals yet. */
/* Read externals from the file */
for (;;) {
xnamp = & syname;
tcread (crlfile, xnamp, 1, crlfnam); ++extdlen;
/* Get first byte of external name */
if (syname [0] == '\0') break;
/* If it's zero, we're done. */
while ((*xnamp & 0x80) == 0) {
tcread (crlfile, ++xnamp, 1, crlfnam); ++extdlen;
} /* Read the rest of the symbol */
*xnamp &= 0x7F; /* Strip the 7th bit from last char */
*++xnamp = 0; /* Add null terminator */
printf ("\tEXTERNAL\t%s\n", syname);
/* Put EXTERNAL statement on .CSM */
strcpy (xname [nexts++], syname);
/* Install name in table */
}
/* End of external directory */
printf (";\n");
ftaddr = faddr + extdlen + 2; /* Find function text */
}
/* Read the text and relocation of a function */
readfunc () {
/* Read in the length word for the function text */
tcseek (crlfile, ftaddr-2, CABS, crlfnam);
tcread (crlfile, &ftlen, 2, crlfnam);
/* Get space for the function text, and read it in. */
if ((ftext = alloc (ftlen)) == NULL) return (FALSE);
tcread (crlfile, ftext, ftlen, crlfnam);
/* Read in the size of the relocation info */
tcread (crlfile, &frlen, 2, crlfnam);
/* Read in the relocation data itself */
if ((freloc = alloc (2 * frlen)) == NULL) {
free (ftext);
return (FALSE);
}
tcread (crlfile, freloc, 2 * frlen, crlfnam);
/* Tell the user what happened */
fprintf (STD_ERR, ";\t%d (0x%04x) bytes of text, ", ftlen, ftlen);
fprintf (STD_ERR, "%d relocation directives,\n", frlen);
fprintf (STD_ERR, ";\t%d external functions", nexts);
if (havecdb) {
fprintf (STD_ERR, ", %d external variables,\n", nextvs);
fprintf (STD_ERR, ";\t%d auto variables, %d formal parameters, ",
nautvs, nparvs);
fprintf(STD_ERR, "frame size is %d (0x%04x)\n", framesize, framesize);
}
else fprintf (STD_ERR, "\n");
return (TRUE);
}
/* Make the label table for a function */
bldlbtab () {
nlabs = 0; /* Clear out the label table */
pass1 = TRUE; /* We're doing the label pass */
dotext (); /* Analyze text for line #s. */
doreloc (); /* Get other labels from relocation */
}
/* Make the assembly code for a function */
asmcode () {
pass1 = FALSE; /* We're doing the code pass */
dotext (); /* Output the instructions */
dospool (); /* Output the string pool */
}
/* Walk through the instructions for a function */
dotext () {
char * label; /* Label on the current word */
struct opc_entry * opcent;
/* Set up the initial location counter past the external header */
if (nexts == 0) locctr = 0;
else locctr = 3 * nexts + 3;
retaddr = ftlen; /* Dummy up a return address */
highcode = 0; /* Dummy up a high transfer address */
/* Walk through the instruction sequence */
while (locctr < retaddr) {
/* Look up the opcode */
opcode = ftext [locctr];
for ( opcent = opc_tabl;
(opcode & opcent -> opc_mask) != opcent -> opc_val;
++opcent) ;
/* In code pass, output the opcode, and any label that
may be needed. */
if (!pass1) {
if ((label = findlab (locctr)) != NULL)
printf ("\n%s:", label);
if (opcent -> opc_type != OP_RST6)
printf ("\t%s", opcent -> opc_name);
}
/* Process the opcode and flag the return address */
switch (opcent -> opc_type) {
case OP_SIMPLE: dosimple (); break;
case OP_LXI: dolxi (); break;
case OP_RPSP: dorpsp (); break;
case OP_REG53: doreg53 (); break;
case OP_MVI: domvi (); break;
case OP_DATA1: dodata1 (); break;
case OP_DATA2: dodata2 (); break;
case OP_MOV: domov (); break;
case OP_ARITH: doarith (); break;
case OP_CONRET: doconret (); break;
case OP_RPPSW: dorppsw (); break;
case OP_CONTRA: docontra (); break;
case OP_TRANS: dotrans (); break;
case OP_IARITH: doiarith (); break;
case OP_RST: dorst (); break;
case OP_IO: doio (); break;
case OP_RST6: dorst6 (); break;
case OP_WHAT: dowhat (); break;
default:
fprintf (STD_ERR, "in dotext: can't happen\n");
quit ();
}
if (!pass1) printf ("\n"); /* End assembly line */
}
}
/* ******* Processing routines for the various opcodes ******* */
/* Simple operations */
dosimple () {
if (opcode == RET && locctr >= highcode)
retaddr = locctr + 1;
/* Set the return address from function */
++locctr;
}
/* LXI */
dolxi () {
if (!pass1) {
tab (); /* LXI x, addr */
do_pairsp ((opcode >> 4) & 0x03);
comma ();
do_imm2 ();
}
locctr += 3;
}
/* Register pair (11 = SP) */
dorpsp () {
if (!pass1) {
tab (); /* INX x */
do_pairsp ((opcode >> 4) & 0x03);
}
++locctr;
}
/* Register number in bits 5-3 */
doreg53 () {
if (!pass1) {
tab (); /* INR x */
do_regno ((opcode >> 3) & 0x07);
}
++locctr;
}
/* MVI */
domvi () {
if (!pass1) {
tab (); /* MVI x, opd */
do_regno ((opcode >> 3) & 0x07);
comma ();
do_byte (ftext [locctr+1]);
}
locctr += 2;
}
/* LHLD or SHLD */
dodata2 () {
if (!pass1) {
tab (); /* LHLD addr */
do_addr ();
}
locctr += 3;
}
/* LDA or STA */
dodata1 () {
if (!pass1) {
tab (); /* LDA addr */
do_addr ();
}
locctr += 3;
}
/* MOV */
domov () {
if (!pass1) {
tab (); /* MOV x, y */
do_regno ((opcode >> 3) & 0x07);
comma ();
do_regno (opcode & 0x07);
}
++locctr;
}
/* Arithmetic operations */
doarith () {
if (!pass1) {
tab (); /* ADD x */
do_regno (opcode & 0x07);
}
++locctr;
}
/* Conditional returns */
doconret () {
if (!pass1) {
do_ccode (); /* Rcc */
}
++locctr;
}
/* Register pairs (11 = PSW) */
dorppsw () {
if (!pass1) {
tab ();
do_pairpsw ((opcode >> 4) & 0x03); /* PUSH xx */
}
++locctr;
}
/* Conditional transfers */
docontra () {
if (!pass1) {
do_ccode (); /* Jcc addr */
tab ();
}
do_xaddr ();
locctr += 3;
}
/* Unconditional transfers */
dotrans () {
struct ccc_entry * ccc;
if (!pass1) {
tab (); /* JMP addr */
}
do_xaddr ();
if ((!isreloc (locctr+1)) /* Funny CCC operator? */
&& (ccc = scanccc (textword (locctr+1), CCC_CODE))) {
if (!pass1) {
switch (ccc -> ccc_flags & 0x07) {
case 1: printf ("\n\t db\t");
do_extoff (ftext [locctr+3]);
break;
case 2: printf ("\n\t dw\t");
do_extoff (textword (locctr+3));
break;
case 5: printf ("\n\t db\t");
do_autoff (ftext [locctr+3]);
break;
case 6: printf ("\n\t dw\t");
do_autoff (textword (locctr+3));
break;
}
}
locctr += ccc -> ccc_flags & 0x03; /* Handle funny ops */
}
locctr += 3;
}
/* Immediate arithmetic */
doiarith () {
if (!pass1) {
tab (); /* ADI xx */
do_byte (ftext [locctr+1]);
}
locctr += 2;
}
/* Restarts other than 6 */
dorst () {
if (!pass1) {
tab (); /* RST n */
printf ("%d", (opcode >> 3) & 0x07);
}
++locctr;
}
/* I/O operations */
doio () {
if (!pass1) {
tab (); /* IN 0nnH */
printf ("0%02xh", ftext [locctr+1]);
}
locctr += 2;
}
/* Restart 6 (line number indication) */
dorst6 () {
char label[8]; /* Storage for labels in pass 1 */
/* If this is the label-making pass, assign a label to the
line for the disassembly pass to use. */
if (pass1) {
sprintf (label, "line%d", textword (locctr+1) & 0xFFF);
makelab (label, locctr);
}
/* This is code pass. Copy the source line to the .CSM file */
else {
if (!(textword (locctr+1) & 0xF000)) {
printf ("\n");
slineno (textword (locctr+1) & 0xFFF);
}
}
locctr += 3;
}
/* Unknown operation */
dowhat () {
fprintf (STD_ERR, "; Warning: unknown opcode at location 0x%04x\n",
locctr);
fprintf (STD_ERR, ";\tHex value is %02x.\n");
if (!pass1) {
do_byte (opcode);
}
++locctr;
}
/* Put a register number on the .CSM file */
do_regno (n)
int n; /* Register number */
{
char * regnos;
regnos = "bcdehlma";
printf ("%c", regnos [n]);
}
/* Put a register pair (11=SP) on the .CSM file */
do_pairsp (n)
int n;
{
switch (n) {
case 0: printf ("b"); break;
case 1: printf ("d"); break;
case 2: printf ("h"); break;
case 3: printf ("sp"); break;
}
}
/* Put a register pair (11=PSW) on the .CSM file */
do_pairpsw (n)
int n;
{
switch (n) {
case 0: printf ("b"); break;
case 1: printf ("d"); break;
case 2: printf ("h"); break;
case 3: printf ("psw"); break;
}
}
/* Put a one-byte quantity on the .CSM file */
do_byte (n)
char n;
{
printf ("0%02xh\t\t; %3d", n, n);
if (n >= ' ' && n <= '~')
printf (" ('%c')", n);
}
/* Put a condition code on the .CSM file */
do_ccode () {
switch (opcode >> 3 & 0x07) {
case 0: printf ("nz"); break;
case 1: printf ("z"); break;
case 2: printf ("nc"); break;
case 3: printf ("c"); break;
case 4: printf ("po"); break;
case 5: printf ("pe"); break;
case 6: printf ("p"); break;
case 7: printf ("m"); break;
}
}
/* Put a two-byte immediate operand on the .CSM file */
do_imm2 () {
if (ftext [locctr+3] == DADSP)
do_frsiz (textword (locctr+1));
/* Appears to be a frame size */
else if (ftext [locctr+3] == DADB)
do_autoff (textword (locctr+1));
/* Appears to be an AUTO offset */
else if (textword (locctr-2) == EXTRNS && ftext [locctr+3] == DADD)
do_extoff (textword (locctr+1));
/* Appears to be an external variable offset */
else /* Don't know what it is */
do_laddr (); /* Treat like address for now */
}
/* Put a transfer address on the .CSM file */
do_xaddr () {
struct ccc_entry * ccc;
/* Remember highest transfer address so we can find the last RET */
if (isreloc (locctr+1))
if (textword (locctr+1) > highcode)
highcode = textword (locctr+1);
if (highcode > retaddr) retaddr = ftlen + 1;
if (pass1) return;
/* Handle addresses in C.CCC */
if (isreloc (locctr+1)
|| !(ccc = scanccc (textword (locctr+1), CCC_CODE)))
/* If not in C.CCC */
do_laddr (); /* Treat like data address for now */
else
putccc (ccc);
}
/* Put a data address on the .CSM file */
do_addr () {
struct ccc_entry * ccc;
if (isreloc (locctr+1)
|| !(ccc = scanccc (textword (locctr+1), CCC_DATA)))
/* If not in C.CCC ... */
do_laddr (); /* treat as local for now */
else
putccc (ccc);
}
/* Put a local address on the .CSM file */
do_laddr () {
unsigned addr; /* Address to print */
addr = textword (locctr+1); /* Get the address */
if (isreloc (locctr+1)) { /* Relative address? */
if (addr < 3 * nexts + 3) { /* External? */
printf ("%s", xname [addr / 3 - 1]);
if (addr % 3) printf ("+%d", addr % 3);
}
else printf ("%s", findlab (addr));
}
else if (crldir.crleflag /* Constant external address? */
&& textword (locctr+1) >= crldir.crleloc
&& textword (locctr+1) < crldir.crleloc + crldir.crlelen) {
printf ("SYS$EXTADDR+");
do_extoff (textword (locctr+1) - crldir.crleloc);
}
else {
printf ("0%04xh\t\t; %d", addr); /* Absolute address */
if (addr >= ' ' && addr <= '~')
printf (" ('%c')", addr);
}
}
/* Print a tab */
tab () {
printf ("\t");
}
/* Print a comma */
comma () {
printf (", ");
}
/* Generate dummy labels for the targets of any relocated addresses */
doreloc () {
int xlabno; /* Count of transfer points */
int strno; /* Count of strings */
int i; /* Loop index */
int addr; /* Relocated target address */
char label [8]; /* Label to assign to it */
xlabno = strno = 0;
for (i=(nexts > 0); i<frlen; ++i) { /* Walk the relocation list */
addr = textword (freloc [i]); /* Get target address */
if (addr >= 3 * nexts + 3 /* Internal address? */
&& findlab (addr) == NULL) { /* Labeled yet? */
if (addr >= retaddr) /* String pool? */
sprintf (label, "str%d", ++strno);
else
sprintf (label, "x%d", ++xlabno);
makelab (label, addr);
}
}
}
/* Determine if a particular address is relocatable */
int isreloc (offset)
unsigned offset;
{
int i;
for (i=frlen-1; i>=0; --i)
if (freloc [i] == offset) return (TRUE);
return (FALSE);
}
/* Output the content of the string pool */
dospool () {
char spopen; /* Flag: between quotes on DB */
char comma; /* Flag: need comma on DB */
char * label; /* Label to be printed */
char byte; /* Byte we're working on */
printf ("\n;\tString pool for function %s\n", fname);
spopen = comma = FALSE; /* Haven't opened a quote yet */
while ((locctr < ftlen) && (!findlab (locctr))) ++locctr;
/* Skip any unreacahable epilogue */
while (locctr < ftlen) { /* Walk through string pool */
if (label = findlab (locctr)) { /* Put out any labels */
if (spopen) {
printf ("'");
spopen = FALSE;
}
comma = FALSE;
printf ("\n%s:\tdb\t", label);
}
byte = ftext [locctr]; /* Get a byte from string */
if (byte < ' ' || byte > '~') {
/* Printable? */
if (spopen) { /* No; close out the string */
printf ("'");
spopen = FALSE;
comma = TRUE;
}
if (comma) { /* Put out any needed comma */
printf (", ");
comma = FALSE;
}
printf ("0%02xH", byte); /* Put the byte */
comma = TRUE; /* Need comma next time */
}
else {
if (!spopen) { /* Printable; open a quote */
if (comma) { /* First putting out comma */
printf (", ");
comma = FALSE;
}
printf ("'");
spopen = TRUE;
}
printf ("%c", byte); /* add byte to quoted string */
if (byte == '\'') printf ("'");
}
++locctr; /* advance to next byte in pool */
}
if (spopen) printf ("'");
printf ("\n\n");
}
/* Free the storage allocated for a function's text and relocation */
freefunc () {
free (freloc); freloc = NULL;
free (ftext); ftext = NULL;
}
/* Add a label to the list of relocatable labels */
makelab (str, value)
char * str; /* Name of the label */
unsigned value; /* Relocation offset of the label */
{
/* Never add a second label to a word */
if (findlab (value) != NULL) return;
/* Never define the same label twice */
if (findaddr (str) != ERROR) return;
/* Insert the new definition */
lab_tab [nlabs] . lab_val = value;
strcpy (lab_tab [nlabs++] . lab_name, str);
}
/* Find a label, by address, in the label list */
char * findlab (value)
unsigned value;
{
int i;
for (i=nlabs-1; i>=0; --i)
if (lab_tab [i] . lab_val == value)
return (&(lab_tab [i] . lab_name));
return (NULL);
}
/* Find the address of a label, given its name */
unsigned findaddr (str)
char * str;
{
int i;
for (i=nlabs-1; i>=0; --i)
if (!strcmp (lab_tab [i] . lab_name, str))
return (lab_tab [i] . lab_val);
return (ERROR);
}
/* Extract a word from the function text */
unsigned textword (offset)
unsigned offset; /* Location of the word */
{
return ((ftext [offset+1] << 8) + ftext [offset]);
}
/* Source continues in CTOA2.C */
{